﻿using System;
using System.Collections.Generic;
using System.Timers;
using System.Web;
using System.Net;
using System.Linq;

namespace CY_MVC.Core
{
    /// <summary>
    /// 阻止攻击IP地址的回应
    /// </summary>
    public static class DDosAttackHelper
    {
        private static readonly Dictionary<string, short> IpInComeing = new Dictionary<string, short>();
        private static readonly Dictionary<string, DateTime> IpBanned = new Dictionary<string, DateTime>();

        private static Timer MyTimer;

        public static void Init()
        {
            if (StaticConfig.DDosAttackBannedCount > 0 && StaticConfig.DDosAttackBennedSeconds > 0 &&
                StaticConfig.DDosAttackCheckPerSeconds > 0)
            {
                MyTimer = new Timer { Interval = 1000 * StaticConfig.DDosAttackCheckPerSeconds };
                MyTimer.Elapsed += Elapsed;
                MyTimer.Start();
            }

        }

        public static void Defense(object p_Sender, EventArgs p_E)
        {
            var ip = ClientIP;
            if (IpBanned.ContainsKey(ip))
            {
                HttpContext.Current.Response.StatusCode = 403;
                HttpContext.Current.Response.Status = "403 You don't have permission to access / on this server";
                HttpContext.Current.Response.End();
            }
            else
            {
                try
                {
                    if (!IpInComeing.ContainsKey(ip)) //如果没有当前访问IP的记录就将访问次数设为1
                    {
                        IpInComeing[ip] = 1;
                    }
                    else if (IpInComeing[ip] == StaticConfig.DDosAttackBannedCount) //如果当前IP访问次数等于规定时间段的最大访问次数就拉于“黑名单”
                    {

                        IpBanned.Add(ip, DateTime.Now.AddSeconds(StaticConfig.DDosAttackBennedSeconds));
                        IpInComeing.Remove(ip);
                    }
                    else //正常访问就加次数 1
                    {
                        IpInComeing[ip]++;
                    }
                }
                catch
                { }
            }
        }

        private static void Elapsed(object p_Sender, EventArgs p_E)
        {
            IpInComeing.Clear();
            foreach (var item in IpBanned.ToArray().Where(item => DateTime.Now >= item.Value))
            {
                IpBanned.Remove(item.Key);
            }
        }


        private static string ClientIP
        {
            get
            {
                var res = string.Empty;
                var proxyipstr = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
                if (!string.IsNullOrEmpty(proxyipstr))
                {
                    //可能有代理 
                    if (proxyipstr.IndexOf(".", StringComparison.Ordinal) == -1)    //没有“.”肯定是非IPv4格式 
                        proxyipstr = null;
                    else
                    {
                        IPAddress ip;
                        if (proxyipstr.IndexOf(",", StringComparison.Ordinal) != -1)
                        {
                            //有“,”，估计多个代理。取第一个不是内网的IP。 
                            proxyipstr = proxyipstr.Replace(" ", "").Replace("'", "");
                            var temparyip = proxyipstr.Split(",;".ToCharArray());
                            foreach (string item in temparyip)
                            {
                                if (IPAddress.TryParse(item, out ip)
                                    && item.Substring(0, 3) != "10."
                                    && item.Substring(0, 7) != "192.168"
                                    && item.Substring(0, 7) != "172.16.")
                                {
                                    return item;    //找到不是内网的地址 
                                }
                            }
                        }
                        else if (IPAddress.TryParse(proxyipstr, out ip)) //代理即是IP格式 
                            return proxyipstr;
                        else
                            proxyipstr = null;    //代理中的内容 非IP，取IP 
                    }
                }

                if (string.IsNullOrEmpty(proxyipstr))
                {
                    res = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
                    if (string.IsNullOrEmpty(res))
                    {
                        res = HttpContext.Current.Request.UserHostAddress;
                    }
                }
                return res;
            }
        }
    }

}
